//
//  WNAudioVC.swift
//  WalkNovel
//
//  Created by Kevin on 2023/11/2.
//

import UIKit
import AVFoundation

class WNAudioVC: WNBaseVC {
    
    deinit {
        NotificationCenter.default.removeObserver(self)
        reset()
    }
    
    lazy var playBtn: UIButton = {
        let btn = UIButton.init(type: .custom)
        btn.setImage(UIImage(named: "music_play"), for: .normal)
        btn.setImage(UIImage(named: "music_pause"), for: .selected)
        btn.rx.tap.bind { [weak self] in
            self?.pauseOrPlay()
        }.disposed(by: rx.disposeBag)
        return btn
    }()
    
    lazy var prevBtn: UIButton = {
        let btn = UIButton.init(type: .custom)
        btn.setImage(UIImage(named: "music_prev"), for: .normal)
        btn.rx.tap.bind { [weak self] in
            self?.prev()
        }.disposed(by: rx.disposeBag)
        return btn
    }()
    
    lazy var nextBtn: UIButton = {
        let btn = UIButton.init(type: .custom)
        btn.setImage(UIImage(named: "music_next"), for: .normal)
        btn.rx.tap.bind { [weak self] in
            self?.next()
        }.disposed(by: rx.disposeBag)
        return btn
    }()
    
    lazy var playOrderBtn: UIButton = {
        let btn = UIButton.init(type: .custom)
        btn.setImage(UIImage(named: "music_loop"), for: .normal)
        btn.setImage(UIImage(named: "music_one"), for: .selected)
        btn.rx.tap.bind { [weak self] in
            btn.isSelected = !btn.isSelected
            self?.loop = btn.isSelected ? 1 : 0
        }.disposed(by: rx.disposeBag)
        return btn
    }()
    
    lazy var speedBtn: UIButton = {
        let btn = UIButton.init(type: .custom)
        btn.setImage(UIImage(named: "music_speed"), for: .normal)
        btn.rx.tap.bind { [weak self] in
            self?.showMenu()
        }.disposed(by: rx.disposeBag)
        return btn
    }()
    
    lazy var slider: WNSlider = {
        var slider = WNSlider()
        slider.minimumValue = 0
        slider.maximumValue = 1
        slider.setThumbImage(UIImage(named: "read_setting_light_slider")?.wn_resized(newSize: CGSize(width: 50, height: 50)), for: .normal)
        slider.minimumTrackTintColor = .init(named: "red_FE95B4")
        slider.maximumTrackTintColor = .init(named: "gray_ECE0E4")
        slider.backgroundColor = .clear
        slider.addTarget(self, action: #selector(valurChanged(slider:event:)), for: .valueChanged)
        return slider
    }()
    
    lazy var titleLabel: UILabel = {
        let label = UILabel()
        label.font = .wn_font(name: .bold, size: 14)
        label.textColor = .init(named: "black_333333")
        return label
    }()
    
    lazy var currentTime: UILabel = {
        let label = UILabel()
        label.font = .wn_font(name: .bold, size: 14)
        label.textColor = .init(named: "black_333333")
        return label
    }()
    
    lazy var allTime: UILabel = {
        let label = UILabel()
        label.font = .wn_font(name: .bold, size: 14)
        label.textColor = .init(named: "black_333333")
        label.textAlignment = .right
        return label
    }()
    
    lazy var playImage: UIImageView = {
        let view = UIImageView(image: UIImage(named: "music_wave"))
        view.wn_animation(WNAnimation.wn_audoPlayingArray, 1, 0)
        view.backgroundColor = .randomColor
        return view
    }()
    
    var musicId = ""
    
    var timer: Timer?
    
    var audioPlayer: STKAudioPlayer?
    
    var musicArr = [MusicModel]()
    
    var currentIndex: Int = -1
    
    var isMove: Bool = false
    
    var loop: Int = 0
    
    var rate: Float = 1.0 {
        didSet {
            if audioPlayer != nil {
            }
        }
    }

    var playState: STKAudioPlayerState = []
    
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        navigationController?.interactivePopGestureRecognizer?.isEnabled = false
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        navigationController?.interactivePopGestureRecognizer?.isEnabled = true
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        let session = AVAudioSession.sharedInstance()
        try? session.setCategory(.playback)
        try? session.setActive(true)
    }
    
    override func viewConfig() {
        view.addSubview(titleLabel)
        view.addSubview(playBtn)
        view.addSubview(prevBtn)
        view.addSubview(nextBtn)
        view.addSubview(slider)
        view.addSubview(currentTime)
        view.addSubview(allTime)
        view.addSubview(playOrderBtn)
        view.addSubview(speedBtn)
        view.addSubview(playImage)
        titleLabel.snp.makeConstraints { make in
            make.top.equalTo(NaviTotalHeight+60)
            make.centerX.equalToSuperview()
        }
        playBtn.snp.makeConstraints { make in
            make.top.equalTo(titleLabel.snp.bottom).offset(30)
            make.centerX.equalToSuperview()
            make.width.height.equalTo(42)
        }
        prevBtn.snp.makeConstraints { make in
            make.centerY.equalTo(playBtn.snp.centerY)
            make.left.equalTo(30)
            make.size.equalTo(playBtn.snp.size)
        }
        nextBtn.snp.makeConstraints { make in
            make.centerY.equalTo(playBtn.snp.centerY)
            make.right.equalTo(-30)
            make.size.equalTo(playBtn.snp.size)
        }
        slider.snp.makeConstraints { make in
            make.top.equalTo(playBtn.snp.bottom).offset(30)
            make.left.equalTo(30)
            make.right.equalTo(-30)
            make.height.equalTo(6)
        }
        currentTime.snp.makeConstraints { make in
            make.top.equalTo(slider.snp.bottom).offset(12)
            make.left.equalTo(slider.snp.left)
        }
        allTime.snp.makeConstraints { make in
            make.centerY.equalTo(currentTime.snp.centerY)
            make.right.equalTo(slider.snp.right)
        }
        playOrderBtn.snp.makeConstraints { make in
            make.top.equalTo(slider.snp.bottom).offset(36)
            make.left.equalTo(30)
            make.size.equalTo(playBtn.snp.size)
        }
        speedBtn.snp.makeConstraints { make in
            make.centerY.equalTo(playOrderBtn.snp.centerY)
            make.right.equalTo(-30)
            make.size.equalTo(playBtn.snp.size)
        }
        playImage.snp.makeConstraints { (make) in
            make.center.equalToSuperview()
            make.size.equalTo(CGSize(width: 66, height: 66))
        }
    }
    
    override func dataConfig() {
        pageName = "音频"
        navView.leftClosure = { [weak self] in
            if (self?.musicArr.count ?? 0) > 0 && self?.audioPlayer != nil {
                self?.wn_suspend(1, self!.musicArr[self!.currentIndex])
            }else {
                self?.reset()
                self?.navigationController?.popViewController(animated: true)
            }
        }
        playWithQueue([
            MusicModel(name: "歌曲1", url: Bundle.main.path(forResource: "test1", ofType: ".mp3")!),
            MusicModel(name: "歌曲2", url: Bundle.main.path(forResource: "test2", ofType: ".mp3")!),
            MusicModel(name: "歌曲3", url: Bundle.main.path(forResource: "test3", ofType: ".mp3")!),
            MusicModel(name: "歌曲4", url: Bundle.main.path(forResource: "test4", ofType: ".mp3")!)])
        //URL(fileURLWithPath: )
        //URL(string: )
//                playWithQueue([
//                    MusicModel(name: "歌曲1", url: "http://music.163.com/song/media/outer/url?id=217151.mp3"),
//                    MusicModel(name: "歌曲2", url: "http://music.163.com/song/media/outer/url?id=117151.mp3"),
//                    MusicModel(name: "歌曲3", url: "http://music.163.com/song/media/outer/url?id=217150.mp3")])
    }
}

extension WNAudioVC {
    //开始播放歌曲列表（默认从第一首歌曲开始播放）
    func playWithQueue(_ arr: [MusicModel], _ index: Int = 0) {
        guard arr.count > 0 && index >= 0 && index < arr.count else {
            return
        }
        musicArr = arr
        if audioPlayer != nil {
            audioPlayer?.stop()
            audioPlayer?.clearQueue()
            audioPlayer = nil
        }
        var options = STKAudioPlayerOptions()
        options.flushQueueOnSeek = true
        options.enableVolumeMixer = true
        audioPlayer = STKAudioPlayer(options: options)
        audioPlayer?.meteringEnabled = true
        audioPlayer?.equalizerEnabled = true
        audioPlayer?.volume = 1
        audioPlayer!.delegate = self

        if let str = arr[index].url {
            audioPlayer?.play(URL(fileURLWithPath: str))
            if timer != nil {
                timer?.invalidate()
                timer = nil
            }
            isMove = false
            slider.value = 0
            slider.maximumValue = 1
            currentTime.text = "00:00"
            allTime.text = "00:00"
            timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(tick), userInfo: nil, repeats: true)
            RunLoop.current.add(timer!, forMode: .common)
            for i in 1 ..< arr.count {
                audioPlayer?.queue(URL(fileURLWithPath: arr[Int((index + i) % arr.count)].url ?? ""))
            }
            currentIndex = index
            playImage.startAnimating()
        }
    }
    
    //停止播放
    func reset() {
        playImage.stopAnimating()
        audioPlayer?.stop()
        audioPlayer?.clearQueue()
        audioPlayer = nil
        timer?.invalidate()
        timer = nil
        currentIndex = -1
        loop = 0
        rate = 1
        isMove = false
        titleLabel.text = "Test Music"
        playBtn.isSelected = false
        slider.value = 0
        slider.maximumValue = 1
        currentTime.text = "00:00"
        allTime.text = "00:00"
    }

    //停止播放
    func stop() {
        playImage.stopAnimating()
        audioPlayer?.stop()
        audioPlayer?.clearQueue()
        audioPlayer = nil
        timer?.invalidate()
        timer = nil
        isMove = false
        playBtn.isSelected = false
    }
    
    //单独播放某个歌曲
    func play(_ file: MusicModel) {
        if let str = file.url {
            audioPlayer?.play(URL(fileURLWithPath: str))
        }
    }
    
    //下一曲
    func next(_ playEnd: Bool = false) {
        guard musicArr.count > 0 else {
            return
        }
        if loop == 1 && playEnd {
            playWithQueue(musicArr, currentIndex)
        }else {
            currentIndex = (currentIndex + 1) % musicArr.count
            playWithQueue(musicArr, currentIndex)
        }
    }
    
    //上一曲
    func prev() {
        currentIndex = max(0, currentIndex - 1)
        playWithQueue(musicArr, currentIndex)
    }
    
    func pauseOrPlay() {
        if audioPlayer == nil {
            playWithQueue(musicArr, currentIndex)
        }else {
            if playState == .paused {
                audioPlayer?.resume()
                playImage.startAnimating()
            }else{
                audioPlayer?.pause()
                playImage.stopAnimating()
            }
        }
    }
    
    @objc func valurChanged(slider: UISlider, event: UIEvent) {
        if let touchEvent = event.allTouches {
            for item in touchEvent {
                switch item.phase {
                case .began, .moved:
                    isMove = true
                case .ended:
                    isMove = false
                    audioPlayer?.seek(toTime: Double(slider.value))
                    if playState == .paused {
                        audioPlayer?.resume()
                    }
                default:
                    break
                }
            }
        }
    }
    
    @objc func tick() {
        if playState == .playing && !isMove {
            slider.value = Float(audioPlayer?.progress ?? 0)
            currentTime.text = "\(audioPlayer?.progress ?? 0)".wn_toDuration()
        }
    }
    
    func showMenu() {
        let rateArr: [Float] = [2.0, 1.5, 1.25, 1.0, 0.75, 0.5]
        let item = rateArr.firstIndex(where: { $0 == rate }) ?? 0
        let popMenu = SwiftPopMenu(menuWidth: 100, arrow: .zero, datas: rateArr.map({ "x: \($0)" }), item: item)
        popMenu.didSelectMenuBlock = { [weak self] index in
            self?.rate = rateArr[index]
            popMenu.dismiss()
        }
        popMenu.arrowPoint = .init(x: speedBtn.right-26, y: speedBtn.bottom)
        popMenu.show()
    }
}

extension WNAudioVC: STKAudioPlayerDelegate {
    
    //开始播放歌曲
    func audioPlayer(_ audioPlayer: STKAudioPlayer, didStartPlayingQueueItemId queueItemId: NSObject) {
        if let index = (musicArr.firstIndex { URL(fileURLWithPath: $0.url ?? "") == queueItemId as? URL }) {
            currentIndex = index
        }
    }
    
    //缓冲完毕
    func audioPlayer(_ audioPlayer: STKAudioPlayer, didFinishBufferingSourceWithQueueItemId queueItemId: NSObject) {
        updateNowPlayingInfoCenter()
    }
    
    //播放状态变化
    func audioPlayer(_ audioPlayer: STKAudioPlayer, stateChanged state: STKAudioPlayerState, previousState: STKAudioPlayerState) {
        playState = state
        updateNowPlayingInfoCenter()
    }
    
    //播放结束
    func audioPlayer(_ audioPlayer: STKAudioPlayer, didFinishPlayingQueueItemId queueItemId: NSObject, with stopReason: STKAudioPlayerStopReason, andProgress progress: Double, andDuration duration: Double) {
        print("stopReason====================", stopReason.rawValue)
        if let index = (musicArr.firstIndex { URL(fileURLWithPath: $0.url ?? "") ==  audioPlayer.currentlyPlayingQueueItemId() as? URL }) {
            currentIndex = index
        }
        if stopReason == .eof {
            let index = currentIndex
            stop()
            playWithQueue(musicArr, index)
        }else if stopReason == .error {
            stop()
        }
    }
    
    //发生错误
    func audioPlayer(_ audioPlayer: STKAudioPlayer, unexpectedError errorCode: STKAudioPlayerErrorCode) {
        stop()
        playWithQueue(musicArr, currentIndex)
    }
    
    //更新当前播放信息
    func updateNowPlayingInfoCenter() {
        if currentIndex >= 0 {
            //更新标题
            titleLabel.text = musicArr[currentIndex].name
            playBtn.isSelected = playState == .playing
            slider.maximumValue = Float(audioPlayer?.duration ?? 0)
            allTime.text = "\(audioPlayer?.duration ?? 0)".wn_toDuration()
        }else {
            stop()
        }
    }
}
